home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / dirutil.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  15KB  |  754 lines

  1. /* dirutil.c - MS-DOS directory reading routines
  2.  *
  3.  * Bdale Garbee, N3EUA, Dave Trulli, NN2Z, and Phil Karn, KA9Q
  4.  * Directory sorting by Mike Chepponis, K3MC
  5.  * New version using regs.h by Russell Nelson.
  6.  * Rewritten for Turbo-C 2.0 routines by Phil Karn, KA9Q 25 March 89
  7.  *
  8.  * Added path filter functions and applied to dodir
  9.  * also used by ftpcli.c, added current directory  
  10.  * storage capability (11/92 WA3DSP)
  11.  * Bugfixes in the above by WG7J
  12.  */
  13.  
  14. #include <stdio.h>
  15. #ifndef UNIX
  16. #include <dir.h>
  17. #include <dos.h>
  18. #else
  19. #include <sys/stat.h>
  20. /* There are at least FOUR variants of statfs()... we handle SCO and Linux */
  21. #ifdef M_UNIX
  22. #include <sys/statfs.h>
  23. #define f_bavail f_bfree
  24. #else
  25. #include <sys/vfs.h>
  26. #endif /* M_UNIX */
  27. #endif /* UNIX */
  28. #include <ctype.h>
  29. #include <stdlib.h>
  30. #ifndef UNIX
  31. #include <io.h>
  32. #endif
  33. #include "global.h"
  34. #include "config.h"
  35. #include "proc.h"
  36. #include "session.h"
  37. #include "dirutil.h"
  38. #include "commands.h"
  39.  
  40. #ifdef CALLSERVER
  41. #include <string.h>
  42. #include <alloc.h>
  43. extern char *CDROM; /* buckbook.c: defines CDROM drive letter e.g. "s:"  */
  44. #endif
  45.  
  46. struct dirsort {
  47.     struct dirsort *next;
  48.     struct ffblk de;
  49. };
  50. #define NULLSORT (struct dirsort *)0
  51.  
  52. static void commas __ARGS((char *dest));
  53. static int fncmp __ARGS((char *a, char *b));
  54. static void format_fname_full __ARGS((FILE *file,struct ffblk *sbuf,int full,
  55.     int n));
  56. static void free_clist __ARGS((struct dirsort *this));
  57.  
  58. #ifdef  notdef
  59. static int getdir_nosort __ARGS((char *path,int full,FILE *file));
  60. #endif
  61. static int nextname __ARGS((int command, char *name, struct ffblk *sbuf));
  62. static void print_free_space __ARGS((char *path,FILE *file,int n));
  63.  
  64. static char *wildcardize __ARGS((char *path));
  65. extern void crunch __ARGS((char *buf,char *path));
  66.  
  67. #define REGFILE (FA_HIDDEN|FA_SYSTEM|FA_DIREC)
  68.  
  69. #define insert_ptr(list,new)    (new->next = list,list = new)
  70.  
  71.  
  72. /* Create a directory listing in a temp file and return the resulting file
  73.  * descriptor. If full == 1, give a full listing; else return just a list
  74.  * of names.
  75.  */
  76. FILE *
  77. dir(path,full)
  78. char *path;
  79. int full;
  80. {
  81.     FILE *fp;
  82.  
  83.     if((fp = tmpfile()) != NULLFILE){
  84.         getdir(path,full,fp);
  85.         rewind(fp);
  86.     }
  87.     return fp;
  88. }
  89.  
  90. /* find the first or next file and lowercase it. */
  91. static int
  92. nextname(command, name, sbuf)
  93. int command;
  94. char *name;
  95. struct ffblk *sbuf;
  96. {
  97.     int found;
  98.  
  99.     switch(command){
  100.     case 0:
  101.         found = findfirst(name,sbuf,REGFILE);
  102.         break;
  103.     default:
  104.         found = findnext(sbuf);
  105.     }
  106.     found = found == 0;
  107. #ifndef UNIX
  108.     if(found)
  109.         strlwr(sbuf->ff_name);
  110. #endif
  111.  
  112.     return found;
  113. }
  114.  
  115. /* wildcard filename lookup */
  116. int
  117. filedir(name,times,ret_str)
  118. char *name;
  119. int times;
  120. char *ret_str;
  121. {
  122.     static struct ffblk sbuf;
  123.     int rval;
  124.  
  125.     switch(times){
  126.     case 0:
  127.         rval = findfirst(name,&sbuf,REGFILE);
  128.         break;
  129.     default:
  130.         rval = findnext(&sbuf);
  131.         break;
  132.     }
  133.     if(rval == -1){
  134.         ret_str[0] = '\0';
  135.     } else {
  136.         /* Copy result to output */
  137.         strcpy(ret_str, sbuf.ff_name);
  138.     }
  139.     return rval;
  140. }
  141. /* do a directory list to the stream 
  142.  * full = 0 -> short form, 1 is long
  143. */
  144. int
  145. getdir(path,full,file)
  146. char *path;
  147. int full;
  148. FILE *file;
  149. {
  150.     struct ffblk *sbuf;
  151.     int command = 0;
  152.     int n = 0;
  153.     struct dirsort *head, *here, *new;
  154.  
  155.     sbuf = mallocw(sizeof *sbuf);
  156.     path = wildcardize(path);
  157.  
  158.     head = NULLSORT;        /* No head of chain yet... */
  159.     for(;;){
  160.         if (!nextname(command, path, sbuf))
  161.             break;
  162.         command = 1;    /* Got first one already... */
  163.         if (sbuf->ff_name[0] == '.')     /* drop "." and ".." */
  164. #ifdef UNIX
  165.             if (sbuf->ff_name[1] == '\0' || (sbuf->ff_name[1] == '.' &&
  166.                              sbuf->ff_name[2] == '\0'))
  167. #endif
  168.             continue;
  169.  
  170.         new = (struct dirsort *) mallocw(sizeof(struct dirsort));
  171.         memcpy(&new->de, sbuf, sizeof *sbuf); /* Copy contents of directory entry struct */
  172.  
  173.         /* insert it into the list */
  174.         if (!head || fncmp(new->de.ff_name, head->de.ff_name) < 0) {
  175.             insert_ptr(head, new);
  176.         } else {
  177.             register struct dirsort *this;
  178.             for (this = head;
  179.                 this->next != NULLSORT;
  180.                 this = this->next)
  181.                 if (fncmp(new->de.ff_name, this->next->de.ff_name) < 0)
  182.                     break;
  183.             insert_ptr(this->next, new);
  184.         }
  185.     } /* infinite FOR loop */
  186.  
  187.     for (here = head; here; here = here->next)
  188.         format_fname_full(file,&here->de,full,++n);
  189.  
  190.     /* Give back all the memory we temporarily needed... */
  191.     free_clist(head);
  192.     free(sbuf);
  193.  
  194.     if(full)
  195.         print_free_space(path, file, n);
  196.  
  197.     return 0;
  198. }
  199.  
  200. static int
  201. fncmp(a,b)
  202. register char *a, *b;
  203. {
  204.     int i;
  205.  
  206.     for(;;){
  207.         if (*a == '.')
  208.             return -1;
  209.         if (*b == '.')
  210.             return 1;
  211.         if ((i = *a - *b++) != 0)
  212.             return i;
  213.         if (!*a++)
  214.             return -1;
  215.     }
  216. }
  217.  
  218. #ifdef ALLCMD
  219. /* Change working directory */
  220. int
  221. docd(argc,argv,p)
  222. int argc;
  223. char *argv[];
  224. void *p;
  225. {
  226.     if(argc > 1){
  227.     if (!dir_ok(argv[1],Command->curdirs)) {
  228.         tprintf("Invalid Drive/Directory - %s\n",argv[1]);
  229.         return 1;
  230.     }
  231.     }
  232.     tprintf("Local Directory - %s\n",Command->curdirs->dir);
  233.     return 0;
  234. }
  235. #endif
  236.  
  237. #if (defined(ALLCMD) || defined(ALLSESSIONS))
  238.  
  239. /* List directory to console */
  240. int
  241. dircmd(argc,argv,p)
  242. int argc;
  243. char *argv[];
  244. void *p;
  245. {
  246.     char *path;
  247.     FILE *fp;
  248.     char tmpname[80];
  249.     char **margv;
  250.  
  251.     path=strdup(make_dir_path(argc,argv[1],Command->curdirs->dir));
  252.     margv = (char **)callocw(2,sizeof(char *));
  253.     tmpnam(tmpname);
  254.     fp = fopen(tmpname,WRITE_TEXT);
  255.     getdir(path,1,fp);
  256.     free(path);
  257.     fclose(fp);
  258.     margv[1] = strdup(tmpname);
  259.     morecmd(2,margv,p);
  260.     free(margv[1]);
  261.     free(margv);
  262.     unlink(tmpname);
  263.     return 0;
  264. }
  265.  
  266. int
  267. dodir(argc,argv,p)
  268. int argc;
  269. char *argv[];
  270. void *p;
  271. {
  272.     char **pargv;
  273.     int i;
  274.  
  275.     if(Curproc->input == Command->input) {
  276.     /* Make private copy of argv and args,
  277.      * spawn off subprocess and return.
  278.      */
  279.     pargv = (char **)callocw((unsigned)argc,sizeof(char *));
  280.     for(i=0;i<argc;i++)
  281.         pargv[i] = strdup(argv[i]);
  282.     newproc("dir",512,(void (*)__ARGS((int,void*,void*)))dircmd,argc,(void *)pargv,p,1);
  283.     } else
  284.     dircmd(argc,argv,p);
  285.     return 0;
  286. }
  287.  
  288. #endif
  289.  
  290. #ifdef ALLCMD
  291. /* Create directory */
  292. int
  293. domkd(argc,argv,p)
  294. int argc;
  295. char *argv[];
  296. void *p;
  297. {
  298.     char path[128];
  299.     
  300.     strcpy(path,make_fname(Command->curdirs->dir,argv[1]));
  301.     
  302. #ifdef UNIX
  303.     if(mkdir(path, 0777) == -1)
  304. #else
  305.     if(mkdir(path) == -1)
  306. #endif
  307.         tprintf("Can't make %s: %s\n",path,sys_errlist[errno]);
  308.     return 0;
  309. }
  310.  
  311. /* Remove directory */
  312. int
  313. dormd(argc,argv,p)
  314. int argc;
  315. char *argv[];
  316. void *p;
  317. {
  318.     char path[128];
  319.     
  320.     strcpy(path,make_fname(Command->curdirs->dir,argv[1]));
  321.     if(rmdir(path) == -1)
  322.         tprintf("Can't remove %s: %s\n",path,sys_errlist[errno]);
  323.     return 0;
  324. }
  325. #endif /*ALLCMD*/
  326.  
  327. /*
  328.  * Return a string with commas every 3 positions.
  329.  * the original string is replace with the string with commas.
  330.  *
  331.  * The caller must be sure that there is enough room for the resultant
  332.  * string.
  333.  *
  334.  *
  335.  * k3mc 4 Dec 87
  336.  */
  337. static void
  338. commas(dest)
  339. char *dest;
  340. {
  341.     char *src, *core;       /* Place holder for malloc */
  342.     unsigned cc;            /* The comma counter */
  343.     unsigned len;
  344.  
  345.     len = strlen(dest);
  346.     /* Make a copy, so we can muck around */
  347.     core = src = strdup(dest);
  348.  
  349.     cc = (len-1)%3 + 1;     /* Tells us when to insert a comma */
  350.  
  351.     while(*src != '\0'){
  352.         *dest++ = *src++;
  353.         if( ((--cc) == 0) && *src ){
  354.             *dest++ = ','; cc = 3;
  355.         }
  356.     }
  357.     free(core);
  358.     *dest = '\0';
  359. }
  360. /* fix up the filename so that it contains the proper wildcard set */
  361. static char *
  362. wildcardize(path)
  363. char *path;
  364. {
  365.     static struct ffblk sbuf;
  366. #ifdef UNIX
  367.     static char ourpath[1024];
  368. #else
  369.     static char ourpath[64];
  370. #endif
  371.  
  372.     /* Root directory is a special case */
  373.     if(path == NULLCHAR ||
  374.        *path == '\0' ||
  375.        strcmp(path,"\\") == 0 ||
  376.        strcmp(path,"/") == 0)
  377. #ifdef UNIX
  378.         path = "/*";
  379. #else
  380.         path = "\\*.*";
  381. #endif
  382. #ifdef CALLSERVER
  383.     if  (CDROM != NULLCHAR &&  strcmp(path, CDROM) == 0)  {
  384.       path = (char *) mallocw(7); /* THIS causes a memory leak ! - WG7J */
  385.       sprintf(path, "%s/*.*", CDROM);
  386.     }
  387. #endif
  388.  
  389.     /* if they gave the name of a subdirectory, append \*.* to it */
  390.     if (nextname(0, path, &sbuf) &&
  391.         (sbuf.ff_attrib & FA_DIREC) &&
  392.         !nextname(1, path, &sbuf)) {
  393.  
  394.         /* if there isn't enough room, give up -- it's invalid anyway */
  395.         if (strlen(path) + 4 > sizeof ourpath - 1) return path;
  396.         strcpy(ourpath, path);
  397. #ifdef UNIX
  398.         strcat(ourpath, "/*");
  399. #else
  400.         strcat(ourpath, "\\*.*");
  401. #endif
  402.         return ourpath;
  403.     }
  404.     return path;
  405. }
  406.  
  407. static void
  408. format_fname_full(file, sbuf, full, n)
  409. FILE *file;
  410. struct ffblk *sbuf;
  411. int full, n;
  412. {
  413. #ifdef UNIX
  414.     static char line_buf[1025];
  415.     static char cbuf[1025];
  416. #else
  417.     char line_buf[50];              /* for long dirlist */
  418.     char cbuf[20];                  /* for making line_buf */
  419. #endif
  420.  
  421.     strcpy(cbuf,sbuf->ff_name);
  422.     if(sbuf->ff_attrib & FA_DIREC) strcat(cbuf, "/");
  423.     if (full) {
  424.         /* Long form, give other info too */
  425.         sprintf(line_buf,"%-13s",cbuf);
  426.         if(sbuf->ff_attrib & FA_DIREC)
  427.             strcat(line_buf,"           ");/* 11 spaces */
  428.         else {
  429.             sprintf(cbuf,"%ld",sbuf->ff_fsize);
  430.             commas(cbuf);
  431.             sprintf(line_buf+strlen(line_buf),"%10s ",cbuf);
  432.         }
  433.         sprintf(line_buf+strlen(line_buf),"%2d:%02d %2d/%02d/%02d%s",
  434. #ifdef UNIX
  435.           sbuf->ff_ftime.tm_hour, sbuf->ff_ftime.tm_min,
  436.           sbuf->ff_ftime.tm_mon + 1, sbuf->ff_ftime.tm_mday,
  437.           sbuf->ff_ftime.tm_year,
  438. #else
  439.           (sbuf->ff_ftime >> 11) & 0x1f,        /* hour */
  440.           (sbuf->ff_ftime >> 5) & 0x3f, /* minute */
  441.           (sbuf->ff_fdate >> 5) & 0xf,  /* month */
  442.           (sbuf->ff_fdate ) & 0x1f,             /* day */
  443.           (sbuf->ff_fdate >> 9) + 80,   /* year */
  444. #endif
  445.           (n & 1) ? "   " : "\n");
  446.         fputs(line_buf,file);
  447.     } else {
  448.         fputs(cbuf,file);
  449.         fputs("\n",file);
  450.     }
  451. }
  452. /* Provide additional information only on DIR */
  453. static void
  454. print_free_space(path, file, n)
  455. char *path;
  456. FILE *file;
  457. int n;
  458. {
  459.     unsigned long free_bytes, total_bytes;
  460.     char s_free[11], s_total[11];
  461.     char cbuf[20];
  462. #ifdef UNIX
  463.     char *pbuf;
  464.     struct statfs vfsb;
  465.     char *cp;
  466.  
  467.     pbuf = mallocw(1024);
  468.     strcpy(pbuf, path);
  469.     if ((cp = strrchr(pbuf, '/')) == 0)
  470.         strcat(pbuf, "/.");
  471.     else
  472.     {
  473.         *++cp = '.';
  474.         *++cp = '\0';
  475.     }
  476. #ifdef M_UNIX
  477.     statfs(pbuf, &vfsb, sizeof vfsb, 0);
  478. #else
  479.     statfs(pbuf, &vfsb);
  480. #endif
  481.     free_bytes = vfsb.f_bsize * vfsb.f_bavail;
  482.     total_bytes = vfsb.f_bsize * vfsb.f_blocks;
  483. #else
  484.     struct dfree dtable;
  485.     unsigned long bpcl;
  486.     char resolved[80];      /* may need as little as 67 */
  487.     union REGS regs;
  488.     struct SREGS sregs;
  489.     int drive;
  490.  
  491.     /* do an undocumented call to find wich drive this mane resolves to */
  492.     regs.x.si = FP_OFF(path);
  493.     sregs.ds = FP_SEG(path);
  494.     regs.x.di = FP_OFF(resolved);
  495.     sregs.es = FP_SEG(resolved);
  496.     regs.h.ah = 0x60;
  497.     intdosx(®s,®s,&sregs);
  498.     drive = resolved[0] - '@';
  499.  
  500.     /* Find disk free space */
  501.     getdfree(drive,&dtable);
  502.  
  503.     bpcl = dtable.df_bsec * dtable.df_sclus;
  504.     free_bytes  = dtable.df_avail * bpcl;
  505.     total_bytes = dtable.df_total * bpcl;
  506. #endif
  507.  
  508.     if(n & 1)
  509.         fputs("\n", file);
  510.  
  511.     sprintf(s_free,"%ld",free_bytes);
  512.     commas(s_free);
  513.     sprintf(s_total,"%ld",total_bytes);
  514.     commas(s_total);
  515.  
  516.     if(n)
  517.         sprintf(cbuf,"%d",n);
  518.     else
  519.         strcpy(cbuf,"No");
  520.  
  521.     fprintf(file,"%s file%s. %s bytes free. Disk size %s bytes.\n",
  522.         cbuf,(n==1? "":"s"),s_free,s_total);
  523. }
  524. static void
  525. free_clist(this)
  526. struct dirsort *this;
  527. {
  528.     struct dirsort *next;
  529.  
  530.     while (this != NULLSORT) {
  531.         next = this->next;
  532.         free(this);
  533.         this = next;
  534.     }
  535. }
  536. #ifdef  notdef
  537. static int
  538. getdir_nosort(path,full,file)
  539. char *path;
  540. int full;
  541. FILE *file;
  542. {
  543.     struct ffblk sbuf;
  544.     int command;
  545.     int n = 0;      /* Number of directory entries */
  546.  
  547. /*      path = wildcardize(path); */
  548.     command = 0;
  549.     while(nextname(command, path, &sbuf)){
  550.         command = 1;    /* Got first one already... */
  551.         if (sbuf.ff_name[0] == '.')     /* drop "." and ".." */
  552.             continue;
  553.         format_fname_full(file, &sbuf, full, ++n);
  554.     }
  555.     if(full)
  556.         print_free_space(path, file, n);
  557.     return 0;
  558. }
  559. #endif
  560.  
  561. /* Translate those %$#@!! backslashes to proper form */
  562. void
  563. undosify(s)
  564. char *s;
  565. {
  566.     while(*s != '\0'){
  567.         if(*s == '\\')
  568.             *s = '/';
  569.         s++;
  570.     }
  571. }
  572.  
  573. char *
  574. make_dir_path(int count,char * arg,char * curdir)         
  575. {
  576. #ifdef UNIX
  577.     char path[1024], *q;
  578. #else
  579.     char path[128], *q;
  580. #endif
  581.  
  582.     undosify(arg);
  583.     undosify(curdir);
  584.     if (count>=2) {
  585.        q=arg;
  586.        q+=strlen(arg)-1;        
  587.        if (*q=='/' || *q==':') {
  588.           strcpy(path,arg);
  589. #ifdef UNIX
  590.           strcat(path, "*");
  591. #else
  592.           strcat(path,"*.*");
  593. #endif
  594.        } else
  595.           strcpy(path,arg);
  596.     } else {
  597. #ifdef UNIX
  598.        strcpy(path, "*");
  599. #else
  600.        strcpy(path,"*.*");
  601. #endif
  602.     }
  603.     return (make_fname(curdir,path));
  604. }        
  605.  
  606. char*
  607. make_fname(char * curdir, char * fname)
  608. {
  609.     char *p;
  610. #ifdef UNIX
  611.     static char new_name[1024];
  612. #else
  613.     static char new_name[128];
  614. #endif
  615.  
  616.     strcpy(new_name,curdir);
  617.     undosify(fname);
  618. #ifdef UNIX
  619.     if (fname[0]=='/') {
  620. #else
  621.     if (fname[0]=='/' || (strchr(fname,':') != NULLCHAR) ) {
  622. #endif
  623.       return fname;
  624.     } else {
  625.       p=new_name;
  626.       p+=strlen(p)-1;
  627.       if (*p=='/')
  628.            *p='\0';
  629.       crunch(new_name,fname);
  630.       return new_name;
  631.     }
  632. }
  633.  
  634. /* Check Drive/Directory for validity - 1=OK, 0=NOGOOD */
  635.  
  636. int
  637. dir_ok(char * newpath,struct cur_dirs * dirs)
  638. {
  639. #ifdef UNIX
  640.     char *a, curpath[1024];
  641. #else
  642.     char *a, curpath[128];
  643. #endif
  644.     char buf[128],fullpath[128];
  645.     int result;
  646. #ifndef UNIX
  647.     int drive = dirs->drv;
  648. #endif
  649.  
  650.     undosify(newpath);
  651. #ifdef UNIX
  652.     strcpy(buf, newpath);
  653.     strcpy(curpath, dirs->dir);
  654. #else
  655.     a=newpath;
  656.     if ((*(a+1)==':') && (isalpha(*a))){
  657.     drive=toupper(*a)-'@';
  658.     strcpy(buf,a+2);
  659.     if (dirs->curdir[drive]==NULLCHAR) {
  660.         if(!getcurdir(drive,curpath)) {
  661.         undosify(curpath);
  662.         sprintf(fullpath,"%c:/%s",drive+'@',curpath);
  663.         dirs->curdir[drive]=strdup(fullpath);
  664.         dirs->drv=drive;
  665.         dirs->dir=dirs->curdir[drive];
  666.         }
  667.     }
  668.     } else {
  669.     strcpy(buf,newpath);
  670.     }
  671.  
  672.     if((a=dirs->curdir[drive])!=NULLCHAR) {
  673.     if ((*(a+1)==':') && (isalpha(*a))){
  674.         if (*(a+2)=='/')
  675.                strcpy(curpath,a+3);
  676.             else
  677.                strcpy(curpath,a+2);
  678.     } else {
  679.             strcpy(curpath,a);
  680.     }
  681.     } else {
  682.       strcpy(curpath,"");
  683.     }
  684. #endif
  685.  
  686.     if (*buf!='/') {
  687.       crunch(curpath,buf);
  688.     } else {
  689.       strcpy(curpath,buf+1);
  690.     }
  691.     a=curpath;
  692. #ifdef UNIX
  693.     sprintf(fullpath,"%s%s",(*a!='/' ? "/" : ""),curpath);
  694. #else
  695.     sprintf(fullpath,"%c:%s%s",drive+'@',(*a!='/' ? "/" : ""),curpath);
  696. #endif
  697.     if((result=access(fullpath,0)+1)==1) {
  698. #ifdef UNIX
  699.     free(dirs->dir);
  700.     dirs->dir = strdup(fullpath);
  701. #else
  702.     if(dirs->curdir[drive])
  703.         free(dirs->curdir[drive]);
  704.     dirs->curdir[drive]=strdup(fullpath);
  705.     dirs->drv=drive;
  706.     dirs->dir=dirs->curdir[drive];
  707. #endif
  708.     }
  709.     return result;
  710. }
  711.  
  712. char *
  713. init_dirs(struct cur_dirs * dirs)
  714. {
  715. #ifdef UNIX
  716.     dirs->dir = getcwd(NULL, 1024);
  717.     return dirs->dir;
  718. #else
  719.     char fullpath[128];
  720.     char buf[128];
  721.     int x;
  722.     int drive;
  723.  
  724.     for(x=0;x<=26;x++)
  725.        dirs->curdir[x]='\0';
  726.  
  727.     drive=getdisk()+1;
  728.     getcurdir(drive,buf);
  729.     undosify(buf);
  730.     sprintf(fullpath,"%c:/%s",drive+'@',buf);
  731.     dirs->curdir[drive]=strdup(fullpath);
  732.     dirs->drv=drive;
  733.     dirs->dir=dirs->curdir[drive];
  734.     return dirs->curdir[drive];
  735. #endif
  736. }
  737.  
  738. void
  739. free_dirs(struct cur_dirs * dirs)
  740. {
  741. #ifdef UNIX
  742.     free(dirs->dir);
  743. #else
  744.     int x;
  745.  
  746.     for(x=0;x<=26;x++) {
  747.         if (dirs->curdir[x])
  748.             free(dirs->curdir[x]);
  749.     }
  750. #endif
  751. }
  752.  
  753.  
  754.